﻿using System;
using System.Collections.Generic;
using System.Text;

namespace WpfBeyond
{
    class reback_Head
    {
        public UInt16 tag = 0xFEFD;
        public UInt16 version = 0x100;
        public UInt32 SessionId = 0;
        public Byte type = 0;/*1：主动上报； 2：被动回传*/
        public UInt16 length = 0;/*数据包长度*/
    }

    /// <summary>
    /// 0x10：终端心跳
    /// </summary>
    class reback_Heartbeat
    {
        /*1： 空闲，终端在线，但未进行任何广播操作；
        2：工作，终端进行广播中；
        3：故障，终端处于故障状态。*/
        public Byte status = 0;
        /*终端通电启动后第一次注册标识：
        1：首次注册；
        2： 非首次注册。*/
        public Byte firstReg = 0;
        public Byte sn_len = 0;
        public string sn = "";
    }

    /// <summary>
    /// 0x11 查询指令应答
    /// </summary>
    class reback_Query
    {
        public Byte code;//结果代码
        public UInt16 len;//长度

        public Byte param_num;//查询参数个数
        public List<param_info> param_tag_list = new List<param_info>();
    }

    /// <summary>
    /// 0x13：终端故障与恢复
    /// </summary>
    class reback_Error
    {
        //1：发生故障
        //2：故障消除，即恢复正常
        public Byte flag;//故障恢复标识

        //1：电源电流过低
        //2：平均电源功耗过低
        //3：功放输出电压过低
        //4：锁定频率场强过低
        //5：无法获取监测信息
        public Byte type;//故障类型

        //发生故障或者故障恢复的描述信息
        public byte[] descript = new byte[255];

        public byte[] time = new byte[4];//UTC时间
    }

    /// <summary>
    /// 0x14：终端任务切换
    /// </summary>
    class reback_taskSwitch
    {
        //1： 任务开始
        //2：任务结束
        public Byte flag;//切换标识

        //1：应急节目源
        //2：日常节目源
        //3：电话
        //4：短信
        //5：调音台
        //6： U 盘
        public Byte type;//任务类型

        public byte[] ebmid = new byte[18];

        public byte[] time = new byte[4];//UTC时间
    }

    /// <summary>
    /// 0x15 播发结果
    /// </summary>
    class reback_playResult
    {
        public byte[] ebmid = new byte[18];
        public Byte code;
        public UInt16 len = 0;
        public string msg = "";
        public byte[] begintime = new byte[4];
        public byte[] endtime = new byte[4];
        public int playtimes = 0;
        public byte[] time = new byte[4];//上报时间
    }

    class reback_Body
    {
        public byte[] src_obj;//源对象编码12位
        public string src_obj_str;
        public UInt16 dst_num;
        public byte[] dst_obj;//目的对象编码序列，12*数据目标对象数量
        public List<string> dst_obj_list = new List<string>();
        /*0x10：终端心跳
        0x11：查询指令应答
        0x13：终端故障与恢复
        0x14：终端任务切换
        0x15： 上报播发结果
        0x16： 播发记录上报*/
        public Byte type;
        public UInt16 length;

        public reback_Heartbeat heartbeat;
        public reback_Query query;
        public reback_Error error;

        public reback_taskSwitch taskswitch;
        public reback_playResult result;

    }


    /// <summary>
    /// E协议回传数据包
    /// </summary>
    class RebackPacket
    {
        public reback_Head head = null;
        public reback_Body body = null;
        UInt32 crc = 0;

        public bool Verified = false;

        public RebackPacket()
        {
            head = new reback_Head();
            body = new reback_Body();
        }

        public bool Parse(byte[] data)
        {
            int pos = 0;
            int i, j = 0;

            /*1	包头标记	2	值为0xFEFD。
            2	协议版本号	2	值为0x0200，当前协议采用的版本号，每次发布修定版本需要加1。
            3	会话标识	4	请求数据包在发送端的统一编号，单向递增。请求与应答的会话标识要保持一致。
            4	数据包类型	1	1：请求数据包；2：应答数据包。
            5	签名标识	1	0：不签名；1：验证数据包含对数据包消息体的数据签名。
            6	数据包长度	2	标识为整个应急广播数据包的长度。
            */
            head.tag = (UInt16)(data[0] * 256 + data[1]);

            if (head.tag != 0xFEFD) return false;

            head.version = (UInt16)(data[2] * 256 + data[3]);

            head.SessionId = (UInt32)(data[4] * 256 * 256 * 256 + data[5] * 256 * 256 + data[6] * 256 + data[7]);

            head.type = data[8];

            head.length = (UInt16)(data[9] * 256 + data[10]);

            /*根据长度计算CRC*/
            UInt32 crc32 = CRC32_MPEG.GetCRC32(data, head.length - 4);
            crc = (UInt32)(data[head.length - 4] * 256 * 256 * 256 + data[head.length - 3] * 256 * 256 + data[head.length - 2] * 256 + data[head.length - 1]);

            if (crc32 == crc)
            {
                Verified = true;
            }
            else
            {
                return false;
            }

            /*1	数据源对象编码	9	数据包发送端的资源编码。
            应急广播资源编码采用18位数字码：
            资源类型码（2个数字，固定0612）+序列号7位（序列号位13个BCD，最后一位补0），采用压缩性BCD编码，9字节。
            2	数据目标对象数量	2	数据目标对象数量。
            3	数据目标对象编码序列	9*数据目标对象数量	数据包接收端的资源编码。
            目标对象编码格式同源对象编码。
            4	业务数据类型	
            请求包与应答包对应业务数据类型要保持一致。
            5	业务数据长度	2	业务数据内容长度。
            6	业务数据内容	业务数据长度	业务数据内容根据业务数据类型不同。
            */
            StringBuilder sb = new StringBuilder();
            pos = 11;
            body.src_obj = new byte[12];
            for (i = 0; i < 12; i++)
            {
                body.src_obj[i] = data[pos++];
            }

            //wangm:2020-6-3 心跳有些带DST_NUM=1,有些DST_NUM=0，注意，这里只是跳过，不解析
            body.dst_num = (UInt16)(data[pos] * 256 + data[pos + 1]);
            pos = pos + 2;

            body.dst_obj = new byte[body.dst_num * 12];
            for (j = 0; j < body.dst_num * 12; j++)
            {
                body.dst_obj[j] = data[pos++];
            }

            body.type = data[pos];
            pos++;

            body.length = (UInt16)(data[pos] * 256 + data[pos + 1]);
            pos = pos + 2;

            if (body.type == 0x11) //查询应答数据
            {
                body.query = new reback_Query();

                body.query.code = data[pos++];

                body.query.len = (UInt16)(data[pos] * 256 + data[pos + 1]);
                pos = pos + 2;

                body.query.param_num = data[pos++];
                
                for (i = 0; i < body.query.param_num; i++)
                {
                    param_info param = new param_info();

                    param.Tag = data[pos++];
                    param.len = data[pos++];

                    param.content = new byte[param.len];
                    Array.Copy(data, pos, param.content, 0, param.len);
                    body.query.param_tag_list.Add(param);
                    pos += param.len;
                }
            }
            else //请求数据包
            {
                /*终端心跳*/
                //if (body.type == 0x10)
                //{
                //    body.heartbeat = new reback_Heartbeat();

                //    body.heartbeat.status = data[pos++];
                //    body.heartbeat.firstReg = data[pos++];
                //    body.heartbeat.sn_len = data[pos++];

                //    //BCD编码
                //    sb.Remove(0, sb.Length);
                //    for (i = 0; i < body.heartbeat.sn_len; i++)
                //    {
                //        sb.Append(data[pos + i].ToString("X2"));
                //    }
                //    body.heartbeat.sn = sb.ToString();
                //    //body.p_heartbeat.sn = ASCIIEncoding.Default.GetString(data, pos, body.p_heartbeat.sn_len);

                //    pos = pos + body.heartbeat.sn_len;

                //    //ParseReback(data, (int)body.p_heartbeat.ext_len, pos);
                //}
            }

            return true;
        }


    }
}
